//==============================================================================
//
//               Copyright (C) 2004  Dick van Oudheusden
//  
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2004-08-25 16:11:39 $ $Revision: 1.11 $
//
//==============================================================================

#include <stdlib.h>

#include "ofc/config.h"

#include "ofc/DXML.h"

#include "ofc/DFile.h"

#include "DInc.h"
#include "DTest.h"

//-Misc------------------------------------------------------------------------

#ifdef HAVE_DXML

static char name[]     = "test.xml";

static char result[]   = 
"<?xml  version=\"1.0\" standalone=\"no\"?><!-- This is a test file for the ofc-library --><TEST>\n\
<BOOK>\n\
<TITLE>Title</TITLE>\n\
<AUTHOR>\n\
<NAME>Owner</NAME>\n\
<AGE>105</AGE>\n\
<FIRSTBOOK></FIRSTBOOK>\n\
</AUTHOR>\n\
<PUBLISHER>Publisher</PUBLISHER>\n\
<DATE>&quot;01/01/2004&quot;</DATE>\n\
<PAGES>200</PAGES>\n\
<STATUS>PLANNED;</STATUS>\n\
<REVIEW>This book is the &lt;best&gt;.</REVIEW>\n\
<AVAILABLE></AVAILABLE>\n\
<![CDATA[This book is the <best> but $long$.]]>\n\
</BOOK>\n\
</TEST>";

@interface DXMLTest : Object <DXMLHandler>
{
@private
  int    _counter; // the check counter
}

- (DXMLTest *) init;
- free;
- (BOOL) startDocument :(const DXMLChar *) version :(const DXMLChar *) encoding :(int) standalone;
- (BOOL) endDocument;
- (BOOL) startElement :(const DXMLChar *) name;
- (BOOL) attribute :(const DXMLChar *) attribute :(const DXMLChar *) value;
- (BOOL) endElement;
- (BOOL) characters :(const DXMLChar *) text;
- (BOOL) comment :(const DXMLChar *) text;
- (BOOL) processingInstruction :(const DXMLChar *) target :(const DXMLChar *) value;
- (BOOL) startCDATA;
- (BOOL) endCDATA;
- (BOOL) startNamespace :(const DXMLChar *) prefix :(const DXMLChar *) uri;
- (BOOL) endNamespace;
- (BOOL) unparsed :(const DXMLChar *) text;
- (void) error :(int) number :(const char *) name :(int) lineNumber :(int) columnNumber;
        
@end


@implementation DXMLTest 


- (DXMLTest *) init
{
  [super init];

  _counter = 0;
  
  return self;
}


- free
{
  return [super free];
}

//
// Process the start of a document
// 
// @param version      the version number
// @param encoding     the encoding
// @param standaline   is the xml document standalone ?
// 
// @return success
// 
- (BOOL) startDocument :(const DXMLChar *) version :(const DXMLChar *) encoding :(int) standalone
{
  // printf("StartDocument: %s %s %d\n", version, encoding, standalone);

  TEST(_counter == 0);
  
  TEST(strcmp(version, "1.0") == 0);
  
  _counter++;
  
  return YES;
}

//
// Process the end of a document
// 
// @return success
// 
- (BOOL) endDocument 
{
  // printf("EndDocument\n");

  TEST(_counter == 23);
  
  _counter++;
  
  return YES;
}

//
// Process the start of an element
// 
// @param name     the name of the element
// 
// @return success
// 
- (BOOL) startElement :(const DXMLChar *) name
{
  // printf("StartElement: %s\n", name);
  
  switch(_counter)
  {
  case 2: TEST(strcmp(name, "TagA") == 0); break;
  case 7: TEST(strcmp(name, "www.test.org|TagB") == 0); break;
  case 15: TEST(strcmp(name, "www.null.org|TagD") == 0); break;
  case 17: TEST(strcmp(name, "www.null.org|TagE") == 0); break;
  default: TEST(NO); break;
  }
  
  _counter++;
  
  return YES;
}

//
// Process an attribute for an element
// 
// @param attribute  the attribute
// @param value      the value for the attribute
// 
// @return success
// 
- (BOOL) attribute :(const DXMLChar *) attribute :(const DXMLChar *) value
{
  // printf("Attribute: %s %s\n", attribute, value);

  switch(_counter)
  {
  case 3: TEST(strcmp(attribute, "AttA") == 0);
          TEST(strcmp(value,     "ValA") == 0);
          break;
  case 4: TEST(strcmp(attribute, "AttB") == 0);
          TEST(strcmp(value,     "ValB") == 0);
          break;
  case 8: TEST(strcmp(attribute, "www.foo.org|AttC") == 0);
          TEST(strcmp(value,     "ValC") == 0);
          break;
  case 9: TEST(strcmp(attribute, "www.test.org|AttD") == 0);
          TEST(strcmp(value,     "ValD") == 0);
          break;
  case 16:TEST(strcmp(attribute, "AttE") == 0);
          TEST(strcmp(value,     "ValE") == 0);
          break;
  default: TEST(NO); break;
  }
  
  _counter++;
  
  return YES;
}

//
// Process the end of an element
// 
// @return success
//
- (BOOL) endElement
{
  // printf("EndElement\n");

  switch(_counter)
  {
  case 11: break;
  case 18: break;
  case 19: break;
  case 22: break;
  default: TEST(NO); break;
  }
  
  _counter++;
  
  return YES;
}

//
// Process a string of characters
// 
// @param text     the text of the characters
// 
// @return success
// 
- (BOOL) characters :(const DXMLChar *) text
{
  // printf("Characters: |%s|\n", text);

  TEST(_counter == 10);
  
  TEST(strcmp(text, "Text") == 0);
  
  _counter++;
  
  return YES;
}

//
// Process a comment
// 
// @param text     the text of the comment
// 
// @return success
// 
- (BOOL) comment :(const DXMLChar *) text
{
  // printf("Comment: %s\n", text);

  TEST(_counter == 1);
  
  TEST(strcmp(text, "Comment") == 0);
  
  _counter++;
  
  return YES;
}

//
// Process a processing instruction
// 
// @param target   the target
// @param value    the value
// 
// @return success
// 
- (BOOL) processingInstruction :(const DXMLChar *) target :(const DXMLChar *) value
{
  // printf("ProcessingInstruction: %s %s\n", target, value);

  TEST(_counter == 21);
  
  TEST(strcmp(target, "ofc") == 0);
  TEST(strcmp(value, "0.4") == 0);
  
  _counter++;
  
  return YES;
}

//
// Process the start of a CDATA section
// 
// @return success
// 
- (BOOL) startCDATA
{
  // printf("StartCDATA\n");
  
  TEST(NO);
  
  return YES;
}

//
// Process the end of a CDATA section
// 
// @return success
// 
- (BOOL) endCDATA
{
  // printf("EndCDATA\n");

  TEST(NO);
  
  return YES;
}

//
// Start of a namespace declaration
// 
// @param prefix   the prefix
// @param uri      the uri
// 
// @return success
// 
- (BOOL) startNamespace :(const DXMLChar *) prefix :(const DXMLChar *) uri
{
  // printf("StartNamespace: %s %s\n", prefix, uri);

  switch(_counter)
  {
  case 5: TEST(strcmp(prefix, "test") == 0);
          TEST(strcmp(uri,    "www.test.org") == 0);
          break;
  case 6: TEST(strcmp(prefix, "foo") == 0);
          TEST(strcmp(uri,    "www.foo.org") == 0);
          break;
  case 14:TEST(prefix == NULL);
          TEST(strcmp(uri,    "www.null.org") == 0);
          break;
  default: TEST(NO); break;
  }

  _counter++;
  
  return YES;
}

//
// End of a namespace declaration
// 
// @return success
// 
- (BOOL) endNamespace
{
  // printf("EndNamespace\n");

  switch(_counter)
  {
  case 12: break;
  case 13: break;
  case 20: break;
  default: TEST(NO); break;
  }
  
  _counter++;
  
  return YES;
}

//
// Process unparsed text in the xml document (e.g. the DTD)
// 
// @param text     the unparsed text
// 
// @return success
// 
- (BOOL) unparsed :(const DXMLChar *) text
{
  // printf("Unparsed: |%s| \n", text);

  TEST(NO);
  
  return YES;
}

// 
// An error is found during the parsing of the file
// 
// @param number       the error number
// @param name         the name of the config file
// @param lineNumber   the line number in the config file
// @param columnNumber the column number in the config file
// 
// @return success
// 
- (void) error :(int) number :(const char *) name :(int) lineNumber :(int) columnNumber
{
  printf("Error: %d (%s) %s %d %d\n", number, [DXMLReader errorToString :number], name, lineNumber, columnNumber);
}
@end

#endif

void DXML_test()
{
#ifdef HAVE_DXML
  DXMLReader    *reader = [DXMLReader new];
  DXMLWriter    *writer = [DXMLWriter new];
  DText         *xml    = [DText      new];
  DXMLTest      *tester = [DXMLTest   new];
  DXMLTree      *tree   = [DXMLTree   new];
  DFile         *file   = [DFile      new];
  BOOL           ok;
  
  STARTTEST();

  // Test of the xml writer with namespaces
  TEST([writer start :xml :'|']);

  TEST([writer startDocument :"1.0" :NULL :-1]);
  TEST([writer comment :"Comment"]);
  TEST([writer startElement :"TagA"]);
  TEST([writer attribute :"AttA" :"ValA"]);
  TEST([writer attribute :"AttB" :"ValB"]);
  TEST([writer startNamespace :"test" :"www.test.org"]);
  TEST([writer startNamespace :"foo"  :"www.foo.org"]);
  TEST([writer startElement :"www.test.org|TagB"]);
  TEST([writer attribute :"www.foo.org|AttC" :"ValC"]);
  TEST([writer attribute :"www.test.org|AttD" :"ValD"]);
  TEST([writer characters :"Text"]);
  TEST([writer endElement]);
  TEST([writer endNamespace]);
  TEST([writer endNamespace]);
  TEST([writer startNamespace :NULL :"www.null.org"]);
  TEST([writer startElement :"www.null.org|TagD"]);
  TEST([writer attribute :"AttE" :"ValE"]);
  TEST([writer startElement :"TagE"]);
  TEST([writer endElement]);
  TEST([writer endElement]);
  TEST([writer endNamespace]);
  TEST([writer processingInstruction :"ofc" :"0.4"]);
  TEST([writer endElement]);
  TEST([writer endDocument]);
  
  [writer free];

  // printf("Writer Test: %s\n", [xml cstring]);
  
  TEST([xml ccompare :"<?xml version=\"1.0\"?><!--Comment--><TagA AttA=\"ValA\" AttB=\"ValB\"><test:TagB xmlns:test=\"www.test.org\" xmlns:foo=\"www.foo.org\" foo:AttC=\"ValC\" test:AttD=\"ValD\">Text</test:TagB><TagD xmlns=\"www.null.org\" AttE=\"ValE\"><TagE></TagE></TagD><?ofc 0.4?></TagA>"] == 0);
  
  [xml seek :0 :0];
  
  // Test of the xml reader with namespaces
  TEST([reader parse :xml  :"text" :tester :'|']);
  
  [reader free];  
  [tester free];
  
  
  // Test of the xml tree without namespaces  
  ok = [file open :name :"r"];
  
  TEST(ok);
  if (ok)
  {
    [tree read :file :name :EOS];
    
    [file close];
  }
  [file free];
  
  [xml clear];
  
  [tree write :xml :"text"];

  TEST([xml ccompare :result] == 0);
  
  [tree free];
  [xml free];
  
  STOPTEST();

#endif
}

